/*
 * (C) Copyright 2015 Jean-Francois Moine
 * (C) Copyright 2014 Henrik Nordstrom
 *
 * Based on mksunxiboot
 *
 * (C) Copyright 2007-2011
 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>

/* boot head definition from sun4i boot code */
struct boot_file_head {
	uint32_t b_instruction;	/* one intruction jumping to real code */
	uint8_t magic[8];	/* ="eGON.BT0" or "eGON.BT1", not C-style str */
	uint32_t check_sum;	/* generated by PC */
	uint32_t length;	/* generated by PC */
	/*
	 * We use a simplified header, only filling in what is needed
	 * for checksum calculation.
	 */
};

#define STAMP_VALUE                     0x5F0A6C39

/* check sum functon from sun4i boot code */
static int gen_check_sum(struct boot_file_head *head_p)
{
	uint32_t length;
	uint32_t *buf;
	uint32_t loop;
	uint32_t i;
	uint32_t sum;

	length = head_p->length;
//	if ((length & 0x3) != 0)	/* must 4-byte-aligned */
//		return -1;
	buf = (uint32_t *)head_p;
	head_p->check_sum = STAMP_VALUE;	/* fill stamp */
	loop = length >> 2;

	/* calculate the sum */
	for (i = 0, sum = 0; i < loop; i++)
		sum += buf[i];

	/* write back check sum */
	head_p->check_sum = sum;

	return 0;
}

int main(int argc, char *argv[])
{
	struct boot_file_head h, *buf;
	unsigned file_size;
	FILE *f;

	if (argc != 3) {
		printf("Usage: %s file.bin file.code\n"
		       "calculates BROM checksum in boot header of given .bin file and writes to .code file\n"
		       "", argv[0]);
		exit(1);
	}

	f = fopen(argv[1], "rb");
	if (!f) {
		perror("Open input file");
		exit(1);
	}

	fread(&h, 1, sizeof h, f);
	file_size = h.length;			// wanted length

	buf = malloc(file_size);
	memset(buf, 0xff, file_size);
	rewind(f);

	fread(buf, 1, file_size, f);
	fclose(f);

	gen_check_sum(buf);

	f = fopen(argv[2], "wb");
	if (!f) {
		perror("Open output file");
		exit(1);
	}
	fwrite(buf, 1, file_size, f);
	fclose(f);

	return 0;
}
